<template>
	<view class="progress" :style="{'--width': W+'px', '--height': H+'px'}">
		<canvas canvas-id="canvas" class="canvas"
				:start="startStatus" :change:start="animate.start"
				:schedule="schedule" :change:schedule="animate.receiveSchedule"
				:radius="radius" :change:radius="animate.setRadius"
				:width="width" :change:width="animate.setWidth"
				:height="height" :change:height="animate.setHeight"
				:lineWidth="lineWidth" :change:lineWidth="animate.setLineWidth"
				:color="color" :change:color="animate.setColor"
				:style="{width: W+'px', height: H+'px'}">
		</canvas>
		<view class="text">{{num}}%</view>
		<view class="back" 
				:style="{ '--width': radius * 2 + lineWidth + 'px', '--lineWidth': lineWidth + 'px' }"
		></view>
	</view>
</template>

<script>
	export default {
		props: {
			// 加载状态
			status: {
				type: Boolean,
				default: false
			},
			// 加载进度目标值，范围：0-100
			value: {
				type: Number,
				validator: function(v){
					return 0 <= v && v <= 100
				},
				default: 100
			},
			// 圆环半径
			radius: {
				type: Number,
				default: 100
			},
			// 线条大小
			lineWidth: {
				type: Number,
				default: 6
			},
			// 线条颜色
			color: {
				type: String,
				default: '#1ad1e4'
			},
			// canvas宽
			width: {
				type: Number,
				default: 220
			},
			// canvas高
			height: {
				type: Number,
				default: 220
			}
		},
		data() {
			return {
				W: this.width,
				H: this.height,
				targetValue: 0,
				schedule: 0,
				progressTmout: null,
				startStatus: false,
			}
		},
		watch: {
			// 监听状态变化
			status(newVal, oldVal) {
				this.targetValue = this.value / 100
				this.startStatus = newVal
				this.progressInc()
			},
			// 监听目标值变化
			value(newVal, oldVal) {
				if(newVal === oldVal) return
				this.schedule = oldVal / 100
				this.targetValue = newVal / 100
				this.progressInc()
			}
		},
		computed: {
			num(){
				return parseInt(this.schedule * 100)
			}
		},
		methods: {
			// 加载进度计算
			progressInc() {
				clearTimeout(this.progressTmout)
				this.progressTmout = null
				if(this.targetValue === this.schedule) return
				// 目标值大于当前值
				if(this.targetValue > this.schedule){
					this.schedule += 0.01;
					this.schedule = +this.schedule.toFixed(2);
					// loop
					if (this.schedule < this.targetValue) {
						const interval = 35;
						this.progressTmout = setTimeout(this.progressInc, interval);
					}
				}else{
					// 目标值小于当前值
					this.schedule -= 0.01;
					this.schedule = +this.schedule.toFixed(2);
					// loop
					if (this.schedule > this.targetValue) {
						const interval = 35;
						this.progressTmout = setTimeout(this.progressInc, interval);
					}
				}
			},
		}
	}
</script>

<!-- 绘制canvas -->
<script module="animate" lang="renderjs">
	let vv = 0;
	// 进度画圈
	function Progress({ctx, w, h, r, l, c, v}){
		this.ctx = ctx
		this.w = w
		this.h = h
		this.r = r
		this.l = l
		this.c = c
		this.v = v
	}
	Progress.prototype.draw = function(){
		this.ctx.clearRect(0, 0, this.w, this.h)
		this.ctx.beginPath()
		this.ctx.strokeStyle = this.c
		this.ctx.lineWidth = this.l
		this.ctx.lineCap = 'round'
		this.ctx.arc(this.w/2, this.h/2, this.r, Math.PI * 1.5, Math.PI * (1.5 + this.v * 2), false)
		this.ctx.stroke()
	}
	Progress.prototype.transform = function(){
		this.v = vv
	}
	Progress.prototype.render = function(){
		this.transform()
		this.draw()
	}
	
	export default {
		data(){
			return {
				schedule: 0,
				W: 0,
				H: 0,
				R: 0,
				L: 0,
				C: ''
			}
		},
		methods: {
			setRadius(newValue){
				this.R = newValue
			},
			setLineWidth(newValue){
				this.L = newValue
			},
			setColor(newValue){
				this.C = newValue
			},
			setWidth(newValue){
				this.W = newValue
			},
			setHeight(newValue){
				this.H = newValue
			},
			receiveSchedule(newValue, oldValue, ownerVm, vm) {
				vv = newValue
				this.schedule = newValue
			},
			start(newValue){
				let canvasEle = document.querySelectorAll('.canvas>canvas')[0]
				let ctx = canvasEle.getContext('2d')
				let w = this.W
				let h = this.H
				let r = this.R
				let l = this.L
				let c = this.C
				let v = 0
				// 绘制圆圈
				var p = new Progress({ctx, w, h, r, l, c, v});
				function progressAnimate(){
					ctx.clearRect(0, 0, w, h);
					ctx.beginPath();
					p.render()
					p.draw()
					requestAnimationFrame(function() {
						progressAnimate();
					})
				}
				if(newValue){
					progressAnimate();
				}
			},
		}
	}
</script>

<style>
	.progress{
		position: relative;
		width: var(--width);
		height: var(--height);
		display: flex;
		align-items: center;
		justify-content: center;
	}
	.canvas{
		position: relative;
		z-index: 100;
	}
	.text{
		position: absolute;
		width: var(--width);
		height: var(--width);
		font-size: 24px;
		font-weight: 600;
		color: #333333;
		text-align: center;
		line-height: var(--width);
		letter-spacing: 1px;
	}
	.back{
		position: absolute;
		width: var(--width);
		height: var(--width);
		border-radius: 50%;
		border: var(--lineWidth) solid #e1e2ee;
		box-sizing: border-box;
	}
</style>